#include "Component.h"
#include "GameObject.h"
#include "Scene.h"
#include "Transformation.h"
#include "Camera.h"
#include "Logger.h"
#include "Exception.h"

using namespace game_engine;
using namespace game_engine::components;
using namespace game_engine::utils;

///////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
///////////////////////////////////////////////////////////////////////////////

Component::Component(void)
    : type()
{
}

Component::Component(GameObject *obj)
    : type(), object(obj)
{
}

Component::~Component(void)
{
}

///////////////////////////////////////////////////////////////////////////////
// Other public methods
///////////////////////////////////////////////////////////////////////////////

Component* Component::getComponent(GameObject* obj, const string &compType) 
    const throw(...)
{
    Component *res = NULL;

    // Obtain component from object. Throw if not found
    try
    {
        res = obj->getComponent(compType);
    } catch (...)
    {
        string msg("unable to retrieve ");
        msg.append(compType + string(" component, from object "));
        msg.append(obj->getName());
        throw IllegalArgumentException(msg);
    }

    return res;
}

const BOOL Component::keyPressed(const UINT32 key) const
{
    return (object->getScene())->keyPressed(key);
}

void Component::forceKeyState(const UINT32 key, const BOOL pressed)
{
    (object->getScene())->forceKeyState(key, pressed);
}

void Component::initialize(void) throw(...)
{
    // Default implementation does nothing
}

void Component::update(const FLOAT32)
{
    // Default implementation does nothing
}

void Component::render(void) throw(...)
{
    // Default implementation does nothing
}

void Component::finalize(void)
{
    // Default implementation does nothing
}

///////////////////////////////////////////////////////////////////////////////
// Protected methods
///////////////////////////////////////////////////////////////////////////////

const Point Component::computeCameraOffset(void) const throw(...)
{
    // Get the scene's active camera
    GameObject *cam = (object->getScene())->getActiveCamera();
    if (cam == NULL)
    {
        string err("No active camera defined in current scene");
        throw NullPointerException(err);
    }

    // Get active camera position and field of view
    Transformation *camTransf;
    Camera *c;
    try
    {
        camTransf = dynamic_cast<Transformation*> 
            (cam->getComponent("Transformation"));
        c = dynamic_cast<Camera*>(cam->getComponent("Camera"));
    } catch (exception &e)
    {
        string err("Error rendering Terrain component : ");
        err.append(e.what());
        throw RuntimeException(err);
    }

    // Compute offset
    FLOAT32 cameraX = camTransf->getXPosition();
    FLOAT32 cameraY = camTransf->getYPosition();
    Rect view(c->getView());
    FLOAT32 xoff = -cameraX + view.getX() + (view.getWidth() / 2);
	FLOAT32 yoff = -cameraY + view.getY() + (view.getHeight() / 2);
	
    return Point(xoff, yoff);
}

///////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////

const string& Component::getType(void) const
{
    return type;
}

GameObject* Component::getObject(void) const
{
    return object;
}

///////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////

void Component::setType(const string &t)
{
    type = t;
}

void Component::setObject(GameObject *obj)
{
    object = obj;
}
